﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2012 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#ifndef CellMemoryTracker_h
#define CellMemoryTracker_h

// 不能包含前置条件文件，会引起循环依赖。

#ifndef CELL_COMPILER
#	pragma message "MemoryTracker included somewhere CellPrerequisites.h wasn't!"
#endif

// 是否使用的是 GCC 3.1 C++ Std lib
#if CELL_COMPILER == CELL_COMPILER_GNUC && CELL_COMP_VER >= 310 && !defined(STLPORT)
// We need to define a hash function for void*
// For gcc 4.3 see http://gcc.gnu.org/gcc-4.3/changes.html
#   if CELL_COMP_VER >= 430
#       include <tr1/unordered_map>
#   else
#       include <ext/hash_map>
namespace __gnu_cxx
{
	template <> struct hash< void* >
	{
		size_t operator()( void* const & ptr ) const
		{
			return (size_t)ptr;
		}
	};
}

#   endif
#endif

namespace cell
{
/** \addtogroup Core
 * @{
 */
/** \addtogroup Memory
 * @{
 */

#if CELL_MEMORY_TRACKER

/** 该类跟踪内存的分配与释放，并能报告内存统计信息和泄漏。
@note
	该类仅在 Debug 构建模式下可用。
*/
class _CellExport MemoryTracker
{
protected:
	CELL_AUTO_MUTEX

	// Allocation record
	struct Alloc
	{
		size_t bytes;
		unsigned int pool;
		std::string filename;
		size_t line;
		std::string function;

		Alloc() :bytes(0), line(0) {}
		Alloc(size_t sz, unsigned int p, const char* file, size_t ln, const char* func)
			:bytes(sz), pool(p), line(ln)
		{
			if (file)
				filename = file;
			if (func)
				function = func;
		}
	};

	std::string mLeakFileName;
	bool mDumpToStdOut;
	typedef HashMap<void*, Alloc> AllocationMap;
	AllocationMap mAllocations;

	size_t mTotalAllocations;
	typedef std::vector<size_t> AllocationsByPool;
	AllocationsByPool mAllocationsByPool;

	void reportLeaks();

	// protected 构造
	MemoryTracker()
		: mLeakFileName("cell_leaks.log"), mDumpToStdOut(true),
		mTotalAllocations(0)
	{
	}

public:

	/// 设置用于记录内存报告的文件名。
	void setReportFileName(const std::string& name)
	{
		mLeakFileName = name;
	}
	/// 返回报告文件名。
	const std::string& getReportFileName() const
	{
		return mLeakFileName;
	}
	/// 设置是否将内存报告输入到 stdout 。
	void setReportToStdOut(bool rep)
	{
		mDumpToStdOut = rep;
	}
	/// 返回是否将内存报告输入到 stdout 。
	bool getReportToStdOut() const
	{
		return mDumpToStdOut;
	}

	/// 返回当前已分配内存的总大小。
	size_t getTotalMemoryAllocated() const;
	/// 返回指定池的已分配内存大小。
	size_t getMemoryAllocatedForPool(unsigned int pool) const;

	/** 记录已经分配的内存情况。该方法只能由内存管理子系统调用。
	@param ptr 指向已分配内存的指针。
	@param sz 已分配内存的大小，单位为字节（byte）。
	@param pool 分配器使用的池的索引。
	@param file 执行分配调用的文件名。
	@param ln 执行分配时的代码行。
	@param func 执行该次分配调用的函数名。
	*/
	void _recordAlloc(void* ptr, size_t sz, unsigned int pool = 0,
						const char* file = 0, size_t ln = 0, const char* func = 0);
	/** 记录内存释放。 */
	void _recordDealloc(void* ptr);

	~MemoryTracker()
	{
		reportLeaks();
	}

	/// 用于获取内存跟踪器对象实例的静态方法。
	static MemoryTracker& get();
};

#endif

/** @} */
/** @} */

} // end namespace cell

#endif // CellMemoryTracker_h
